'''
Created on 05/06/2012

@author: Administradora :D
'''

from main.ioDevs import IO, Printer
from main.dataStructures import ProcessesQueue
from main.process import PCB, Instruction, Process, ProcessStatus, IOInstruction,ProcessStates
from main.kernel import Kernel
from main.memory import PhysicalMemory,BestAdjustment
import unittest

class TestIODevices(unittest.TestCase):
    def setUp(self):
        self.io = IO()
        self.pcb1 =  PCB(3)
        self.pcb2 =  PCB(6)
        self.pcb3 =  PCB(7)
        self.instruction1 =  IOInstruction(1,'Printer')
        self.instruction2 =  Instruction(ProcessStatus.CPU,2)
        self.instruction3 =  Instruction(ProcessStatus.CPU,3)
        self.instruction4 =  IOInstruction(4,'Printer')
        self.instruction6 =  IOInstruction(6,'Printer')
        self.instruction8 =  IOInstruction(3,'Printer')
        self.instruction9 =  IOInstruction(4,'Printer')
        self.instruction10=  Instruction(ProcessStatus.CPU,10)
        #------------------------------------------#
        self.process1 = Process(self.pcb1)
        self.process1.addInstruction(self.instruction1)
        self.process1.addInstruction(self.instruction2)
        self.process1.addInstruction(self.instruction3)
        self.process1.addInstruction(self.instruction4)
        #------------------------------------------#
        self.process2 = Process(self.pcb2)
        self.process2.addInstruction(self.instruction6)
        #------------------------------------------#
        self.process3 = Process(self.pcb3)
        self.process3.addInstruction(self.instruction8)
        self.process3.addInstruction(self.instruction9)
        self.process3.addInstruction(self.instruction10)
        #------------------------------------------#
        self.processes = ProcessesQueue()
        self.readyProcesses = ProcessesQueue()
        self.io.addIOProcessToQueue(self.process1)
        self.io.addIOProcessToQueue(self.process2)
        self.io.addIOProcessToQueue(self.process3)
        self.memoria = PhysicalMemory(50,BestAdjustment())
        self.kernel = Kernel(None,None,None,self.processes,self.readyProcesses,ProcessesQueue(),self.memoria,None)
        self.devicesPatch = []
        self.devicesPatch.append(Printer(1,self.kernel,self.io.processesUsingADevice))
        self.devicesPatch.append(Printer(2,self.kernel,self.io.processesUsingADevice))
        self.io.devices = self.devicesPatch
        self.myDevice = Printer(3,self.kernel,self.io.processesUsingADevice)
        
    #Testea el metodo dispatch() de IO
    def test_whenIOdispatchAprocess(self):
        self.io.dispatch()                                                  #Toma el primer proceso de la cola de IO y le asigna un Device libre
        self.assertFalse(self.io.devices[0].available)                      #El device asignado al proceso ya no esta libre
        self.assertEquals(self.io.devices[0].currentProcess, self.process1) #El device tiene que ejecutar al proceso1
        self.assertEquals(self.io.processesWaitingForIO.length(), 2)        #En la cola de procesos esperando por IO, quedan 2 procesos de los 3 que habia
    
    #Testea el execute de los IO devices    
    def test_executeAprocessWithMoreThanOneInstruction(self):
        self.memoria.cells[0] = self.instruction1
        self.memoria.cells[1] = self.instruction2
        self.memoria.cells[2] = self.instruction3
        self.memoria.cells[3] = self.instruction4
        self.process1.pcb.baseRegister = 0
        self.memoria.processesTable.append(self.process1)
        self.myDevice.currentProcess = self.process1                              #Se le asigna a un device ,un proceso de IO
        self.io.processesUsingADevice.append(self.process1) 
        #                           
        self.myDevice.execute(self.process1)                                      #El device ejecuta ese proceso
        self.assertEquals(self.process1.pcb.currentInstruction, self.instruction2)#La primera instruccion se ejecuta y la currentInstruction del proceso es ahora la 2
        self.assertEquals(self.process1.pcb.status, ProcessStates().READY)        #Como no fue su ultima instruccion, ele stado del proceso es ready
        self.assertEquals(self.myDevice.currentProcess,None)                      #Termino de ejecutar, el device esta libre
        self.assertTrue(self.myDevice.available)                                  #Device libre
        self.assertEquals(self.process1, self.kernel.readyProcessesQueue.pop(0))  #El proceso que aun no termino esta en la cola de listos esperando por Cpu de nuevo
        
    #Testea el execute de los IO devices (Proceso con una sola instruccion)  
    def test_executeAprocessWithOneInstruction(self):
        self.kernel.processesInSystem.append(self.process2)
        self.memoria.cells[0] = self.instruction6
        self.process2.pcb.baseRegister = 0
        self.memoria.processesTable.append(self.process2)
        self.myDevice.currentProcess = self.process2 
        self.io.processesUsingADevice.append(self.process2)                             #Se le asigna a un device ,un proceso de IO
        self.myDevice.execute(self.process2)   
        self.assertEquals(self.process2.pcb.currentInstruction, None)             #La primera instruccion se ejecuta y la currentInstruction del proceso es ahora la 2
        self.assertEquals(self.process2.pcb.status, ProcessStates().FINISHED)     #El proceso con una instrcuccion termino de ejecutarse
        self.assertEquals(self.myDevice.currentProcess,None)                      #Termino de ejecutar, el device esta libre
        self.assertTrue(self.myDevice.available)                                  #Device libre
        self.assertEquals(self.process2, self.kernel.finishedProcessesQueue.pop(0))#El proceso que termino de ejecutar, se envia en la cola de terminados
        
        
suite = unittest.TestLoader().loadTestsFromTestCase(TestIODevices)
unittest.TextTestRunner(verbosity=2).run(suite)